package com.liuqi.knet.remoting.transport.netty;

import com.liuqi.knet.remoting.Codec;
import com.liuqi.knet.remoting.RemotingException;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import java.util.List;

/**
 * @author liuqi
 * @date 2025/2/8 17:00
 **/
public class NettyCodecAdapter {

    private Codec codec;

    public NettyCodecAdapter(Codec codec) {
        this.codec = codec;
    }

    public ChannelHandler getEncoder() {
        return new InternalEncoder();
    }

    public ChannelHandler getDecoder() {
        return new InternalDecoder();
    }

    private class InternalEncoder extends MessageToByteEncoder {
        protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception {
            try {
                codec.encode(out, msg);
            } catch (Exception e) {
                throw new RemotingException("InternalEncoder failed. ", e);
            }
        }
    }

    private class InternalDecoder extends ByteToMessageDecoder {
        protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception {
            int save = buffer.readerIndex();
            do {
                try {
                    Object obj = codec.decode(buffer);
                    if (obj == Codec.DecodeResult.NEED_MORE_INPUT) {
                        buffer.readerIndex(save);
                        break;
                    } else {
                        out.add(obj);
                        save = buffer.readerIndex();
                    }
                } catch (Exception e) {
                    throw new RemotingException("InternalDecoder failed. ", e);
                }
            } while (buffer.isReadable());
        }
    }

}
